#include "EntityManager.h"
#include "Entity.h"
#include "Level.h"
#include "EntityCollision.h"
#include "CollisionTypes.h"

EntityManager::EntityManager(Level* currentLevel) : _currentLevel(currentLevel) {}

EntityManager::~EntityManager(void)
{
	removeAllEntities();
}

void EntityManager::update()
{
	if (!_removeList.empty())
	{
		for (auto it = _removeList.begin(); it != _removeList.end(); it++)
		{
			(*it)->clean();
			_entities.remove(*it);
			if (((*it)->component() & COMPONENT_COLLIDEABLE) == COMPONENT_COLLIDEABLE)
				_collideables.remove(dynamic_cast<Collideable*>(*it));
			if (((*it)->component() & COMPONENT_DRAWABLE) == COMPONENT_DRAWABLE)
				_drawables.remove(dynamic_cast<Drawable*>(*it));
			delete *it;
			*it = nullptr;
		}
		_removeList.clear();
	}
	
	for (auto it = _entities.begin(); it != _entities.end(); it++)
	{
		(*it)->move();
		_currentLevel->clearFlags(*it);
		_currentLevel->isOnGround(*it);

		if ( ((*it)->flags() & GRAVITY_AFFECTED ) == GRAVITY_AFFECTED )
			_currentLevel->applyGravity(*it);

		if ((((*it)->flags() & GHOST) != GHOST) && (((*it)->component() & COMPONENT_COLLIDEABLE) == COMPONENT_COLLIDEABLE) )
			_currentLevel->checkCollision(*it);	// check collision against level after setting velocity
		(*it)->update();
		if ((*it)->killMe())
			_removeList.push_back(*it);
		(*it)->applyTranslation();
	}

	for (auto it = _collideables.begin(); it != _collideables.end(); it++)
	{
		for (auto it2 = _collideables.begin(); it2 != _collideables.end(); it2++)
		{
			if (it != it2)
			{
				if (!verifyCollisionType(*it, *it2))
					continue;
				if ((*it)->collisionBox().intersects((*it2)->collisionBox()))
				{
					processCollision(dynamic_cast<Entity*>((*it)), dynamic_cast<Entity*>((*it2)));
				}
			}
		}
	}
}

void EntityManager::draw(RenderManager* renderManager)
{
	for (auto it = _drawables.begin(); it != _drawables.end(); it++)
	{
		(*it)->draw(renderManager);
	}
}

void EntityManager::initialize()
{
	for (auto it = _entities.begin(); it != _entities.end(); it++)
	{
		(*it)->initialize();
	}
}

void EntityManager::addEntity(Entity* entity)
{
	_entities.push_back(entity);
	if ((entity->component() & COMPONENT_DRAWABLE) == COMPONENT_DRAWABLE)
	{
		Drawable* drawable = dynamic_cast<Drawable*>(entity);
		_drawables.push_back(drawable);
	}

	if ((entity->component() & COMPONENT_COLLIDEABLE) == COMPONENT_COLLIDEABLE)
	{
		Collideable* collideable = dynamic_cast<Collideable*>(entity);
		_collideables.push_back(collideable);
	}

}

void EntityManager::removeAllEntities()
{
	for (auto it = _entities.begin(); it != _entities.end(); it++)
	{
		(*it)->clean();
		delete *it;
		*it = nullptr;
	}
	_entities.clear();
	_drawables.clear();
	_collideables.clear();
}

bool EntityManager::verifyCollisionType(Collideable* lhs, Collideable* rhs)
{
	for (auto it = lhs->getCollisionTypeBegin(); it != lhs->getCollisionTypeEnd(); it++)
	{
		for (auto it2 = rhs->getMaskFilterBegin(); it2 != rhs->getMaskFilterEnd(); it2++)
		{
			if ((*it) == (*it2))
				return true;
		}
	}
	return false;
}